package rxgo

type ReduceFunc func(interface{}, interface{}) interface{}

func From(in []interface{}) chan interface{} {
	out := make(chan interface{}, len(in))

	for _, val := range in {
		out <- val
	}

	close(out)

	return out
}

func Values(in chan interface{}) []interface{} {
	out := make([]interface{}, 0)
	for val := range in {
		out = append(out, val)
	}

	return out
}
func Reduce(in <-chan interface{}, reduceFunc ReduceFunc, initialVal interface{}) chan interface{} {
	out := make(chan interface{})

	go func() {
		result := initialVal

		for val := range in {
			result = reduceFunc(result, val)
		}

		out <- result
		close(out)
	}()

	return out
}


func Count(in chan interface{})chan interface{}{
	out := make(chan interface{})
	go func(){
		count := 0
		for _= range in{
			count += 1
		}
		out <- count
		close(out)
	}()
	return out
}


func Average(in chan interface{}) chan interface{} {
	out := make(chan interface{})

	go func() {
		defer close(out)
		count := 0
		sum, _ := <-Reduce(in, func(i interface{}, i2 interface{}) interface{} {
			count++
			return i.(int) + i2.(int)
		}, 0)

		if count > 0 {
			avg := sum.(int) / count
			out <- avg
		}
	}()
	return out
}
func Sum(in chan interface{}) chan interface{} {
	return Reduce(in, func(i interface{}, i2 interface{}) interface{} {
		return i.(int) + i2.(int)
	}, 0)
}

func Max(in chan interface{})chan interface{}{
	out:= make(chan interface{})
	go func(){
		var max interface{}
		for item := range in{
			if max == nil{
				max = item
			}else{
				flag := false
				switch item.(type){
				case string:
					flag = item.(string) > max.(string)
				case int:
					flag = item.(int) > max.(int)
				case int8:
					flag = item.(int8) > max.(int8)
				case int16:
					flag = item.(int16) > max.(int16)
				case int32:
					flag = item.(int32) > max.(int32)
				case int64:
					flag = item.(int64) > max.(int64)
				case uint:
					flag = item.(uint) > max.(uint)
				case uint8:
					flag = item.(uint8) > max.(uint8)
				case uint16:
					flag = item.(uint16) > max.(uint16)
				case uint32:
					flag = item.(uint32) > max.(uint32)
				case uint64:
					flag = item.(uint64) > max.(uint64)
				case float32:
					flag = item.(float32) > max.(float32)
				case float64:
					flag = item.(float64) > max.(float64)
				}
				if flag{
					max = item
				}

			}
		}
		if max != nil{
			out <- max
		}
		close(out)
	}()
	return out
}


func Min(in chan interface{})chan interface{}{
	out:= make(chan interface{})
	go func(){
		var min interface{}
		for item := range in{
			if min == nil{
				min = item
			}else{
				flag := false
				switch item.(type){
				case string:
					flag = item.(string) < min.(string)
				case int:
					flag = item.(int) < min.(int)
				case int8:
					flag = item.(int8) < min.(int8)
				case int16:
					flag = item.(int16) < min.(int16)
				case int32:
					flag = item.(int32) < min.(int32)
				case int64:
					flag = item.(int64) < min.(int64)
				case uint:
					flag = item.(uint) < min.(uint)
				case uint8:
					flag = item.(uint8) < min.(uint8)
				case uint16:
					flag = item.(uint16) < min.(uint16)
				case uint32:
					flag = item.(uint32) < min.(uint32)
				case uint64:
					flag = item.(uint64) < min.(uint64)
				case float32:
					flag = item.(float32) < min.(float32)
				case float64:
					flag = item.(float64) < min.(float64)
				}
				if flag{
					min = item
				}

			}
		}
		if min != nil{
			out <- min
		}
		close(out)
	}()
	return out
}

func Concat(chans ...chan interface{})chan interface{}{
	out := make(chan interface{})
	go func(){
	for _, c := range chans{
			for val := range c{
				out <- val
			}
		}
		close(out)
	}()
	return out
}